#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    this->setGeometry(0, 0, 1024, 600);

    /* 布局 */
    videoMonitorLayout();

    /* network初始化 */
    networkInit();

    /* 连接信号与槽 */
    connect(clearBtn, SIGNAL(clicked()), this, SLOT(toClearTextBrowser()));
    connect(captureBtn, SIGNAL(clicked()), this, SLOT(toSaveCapture()));
    connect(upendBtn, SIGNAL(clicked()), this, SLOT(toUpendVideo()));

    connect(upBtn, SIGNAL(clicked()), this, SLOT(toCtrlGimbalUp()));
    connect(downBtn, SIGNAL(clicked()), this, SLOT(toCtrlGimbalDown()));
    connect(leftBtn, SIGNAL(clicked()), this, SLOT(toCtrlGimbalLeft()));
    connect(rightBtn, SIGNAL(clicked()), this, SLOT(toCtrlGimbalRight()));


    connect(connectBtn, SIGNAL(clicked()), this, SLOT(toConnectTcpSocket()));
    connect(disconnectBtn, SIGNAL(clicked()), this, SLOT(toDisconnectTcpSocket()));

    /* 网络相关 */
    connect(this, SIGNAL(readyToRecvUdp()), this, SLOT(toSendAnyUdpData()));
    connect(tcpSocket, SIGNAL(connected()), this, SLOT(tcpConnected()));
    connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(tcpDisconnect()));
    connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(receivedReplyData())); /* 套接字有数据可读 */
    connect(tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this, SLOT(tcpSocketStateChange(QAbstractSocket::SocketState)));     /* 套接字状态改变 */
    connect(udpSocket, SIGNAL(readyRead()), this, SLOT(receivedVideoDataAndShow())); /* 新的套接字连接 */
    connect(udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this, SLOT(udpSocketStateChange(QAbstractSocket::SocketState)));   /* 套接字状态变化 */
}

MainWindow::~MainWindow()
{
}

void MainWindow::videoMonitorLayout()
{
    /* ======= 01.实例化布局对象 ======= */
    netH0Layout = new QHBoxLayout();
    netH1Layout = new QHBoxLayout();
    netH2Layout = new QHBoxLayout();
    netH0Widget = new QWidget();
    netH1Widget = new QWidget();
    netH2Widget = new QWidget();
    netV0Layout = new QVBoxLayout();
    netV0Widget = new QWidget();

    h0Layout = new QHBoxLayout();
    h1Layout = new QHBoxLayout();
    h2Layout = new QHBoxLayout();
    h0Widget = new QWidget();
    h1Widget = new QWidget();
    h2Widget = new QWidget();

    v0Layout = new QVBoxLayout();
    v0Widget = new QWidget();

    hMainLayout = new QHBoxLayout();
    hMainWidget = new QWidget();

    /* ======= 02.实例化空间对象 ======= */
    picLabel = new QLabel();    /* 视频标签 */
    picLabel->setGeometry(10, 10, 800, 480);

    ipLabel = new QLabel();
    ipLabel->setText("I  P: ");
    ipLineEdit = new QLineEdit();
    ipLineEdit->setText(ipString);

    portLabel = new QLabel();
    portLabel->setText("Port: ");
    portLineEdit = new QLineEdit();
    portLineEdit->setText(portString);

    connectBtn = new QPushButton("连接");    /* 连接按键 */
    connectBtn->setMaximumHeight(30);

    disconnectBtn = new QPushButton("断开");    /* 断开按键 */
    disconnectBtn->setMaximumHeight(30);
    disconnectBtn->setEnabled(false);

    captureBtn = new QPushButton("截屏");    /* 截屏按键 */
    captureBtn->setMaximumHeight(30);
    captureBtn->setEnabled(false);

    upendBtn = new QPushButton("倒放");    /* 倒放按键 */
    upendBtn->setMaximumHeight(30);
    upendBtn->setEnabled(false);

    upBtn = new QPushButton("向上");    /* 向上按键 */
    upBtn->setMaximumSize(100, 50);
    upBtn->setEnabled(false);

    downBtn = new QPushButton("向下");    /* 向下按键 */
    downBtn->setMaximumSize(100, 50);
    downBtn->setEnabled(false);

    leftBtn = new QPushButton("向左");    /* 向左按键 */
    leftBtn->setMaximumSize(100, 50);
    leftBtn->setEnabled(false);

    rightBtn = new QPushButton("向右");    /* 向右按键 */
    rightBtn->setMaximumSize(100, 50);
    rightBtn->setEnabled(false);

    textBrowser = new QTextBrowser();       /* 实例化 文本浏览器 */
    clearBtn = new QPushButton("清除");     /* 清除日志按键 */

    /* ======= 03.布局 ======= */
    /* 网络标签 */
    netH0Layout->addWidget(ipLabel);
    netH0Layout->addWidget(ipLineEdit);
    netH0Layout->setContentsMargins(0, 0, 0, 0);
    netH0Widget->setLayout(netH0Layout);

    netH1Layout->addWidget(portLabel);
    netH1Layout->addWidget(portLineEdit);
    netH1Layout->setContentsMargins(0, 0, 0, 0);
    netH1Widget->setLayout(netH1Layout);

    netH2Layout->addWidget(connectBtn);
    netH2Layout->addWidget(disconnectBtn);
    netH2Layout->setContentsMargins(0, 0, 0, 0);
    netH2Widget->setLayout(netH2Layout);

    netV0Layout->addWidget(netH0Widget);
    netV0Layout->addWidget(netH1Widget);
    netV0Layout->addWidget(netH2Widget);
    netV0Layout->setContentsMargins(0, 0, 0, 0);
    netV0Widget->setLayout(netV0Layout);

    /* 截屏和倒放 */
    h0Layout->addWidget(captureBtn);
    h0Layout->addWidget(upendBtn);
    h0Layout->setContentsMargins(0, 0, 0, 0);
    h0Widget->setLayout(h0Layout);

    /* 方向控制 */
    h1Layout->addWidget(upBtn);
    h1Layout->addWidget(downBtn);
    h1Layout->addWidget(leftBtn);
    h1Layout->addWidget(rightBtn);
    h1Layout->setContentsMargins(0, 0, 0, 0);
    h1Widget->setLayout(h1Layout);

    /* 右半布局 */
    netV0Widget->setMaximumHeight(150);

    QSpacerItem *v0_Spacer0 = new QSpacerItem(150, 5, QSizePolicy::Fixed,
                                              QSizePolicy::Fixed);
    QSpacerItem *v0_Spacer1 = new QSpacerItem(150, 5, QSizePolicy::Fixed,
                                              QSizePolicy::Fixed);
    QSpacerItem *v0_Spacer2 = new QSpacerItem(150, 5, QSizePolicy::Fixed,
                                              QSizePolicy::Fixed);
    QSpacerItem *v0_Spacer3 = new QSpacerItem(150, 5, QSizePolicy::Fixed,
                                              QSizePolicy::Fixed);
    QSpacerItem *v0_Spacer4 = new QSpacerItem(150, 5, QSizePolicy::Fixed,
                                              QSizePolicy::Fixed);
    QSpacerItem *v0_Spacer5 = new QSpacerItem(150, 5, QSizePolicy::Fixed,
                                              QSizePolicy::Fixed);

    v0Layout->addSpacerItem(v0_Spacer0);
    v0Layout->addWidget(netV0Widget);
    v0Layout->addSpacerItem(v0_Spacer1);
    v0Layout->addWidget(h0Widget);
    v0Layout->addSpacerItem(v0_Spacer2);
    v0Layout->addWidget(h1Widget);
    v0Layout->addSpacerItem(v0_Spacer3);
    v0Layout->addWidget(textBrowser);
    v0Layout->addSpacerItem(v0_Spacer4);
    v0Layout->addWidget(clearBtn);
    v0Layout->addSpacerItem(v0_Spacer5);
    v0Layout->setContentsMargins(0, 0, 0, 0);
    v0Widget->setLayout(v0Layout);

    /* 水平整体布局布局 */
    v0Widget->setMaximumWidth(250);

    QSpacerItem *h0_Spacer0 = new QSpacerItem(20, 20, QSizePolicy::Fixed,
                                              QSizePolicy::Fixed);

    hMainLayout->addWidget(picLabel);
    hMainLayout->addWidget(v0Widget);
    hMainLayout->addSpacerItem(h0_Spacer0);
    hMainLayout->setContentsMargins(0, 0, 0, 0);

    hMainWidget->setLayout(hMainLayout);

    setCentralWidget(hMainWidget);
}

void MainWindow::networkInit()
{
    /* 实例化TCP */
    tcpSocket = new QTcpSocket();

    /* 实例化UDP */
    udpSocket = new QUdpSocket();
}

/* 输出信息到 textBrowser */
void MainWindow::printLogOnTextBrowser(const QString &logString)
{
    QTime time = QTime::currentTime();
    textBrowser->append("[" + time.toString("hh:mm:ss") + "] " + "LOG: " + logString);
}

void MainWindow::toClearTextBrowser()
{
    textBrowser->clear();
}

void MainWindow::toSaveCapture()
{
    printLogOnTextBrowser("not support save capture");
}

void MainWindow::toUpendVideo()
{
    printLogOnTextBrowser("not support upend video");
}

void MainWindow::toCtrlGimbalUp()
{
    QByteArray btAry;
    QJsonObject jsonObj;

    /* {"cmd":"control", "action":"up", "appid":"1000", "deviceid":"0001"} */
    jsonObj.insert("cmd", "control");
    jsonObj.insert("action", "up");
    jsonObj.insert("appid", "1000");
    jsonObj.insert("deviceid", "0001");

    /* 将json格式转换为byte数组 */
    QJsonDocument jsonDoc(jsonObj);
    btAry = jsonDoc.toJson();

    /* 往套接字写入数据 */
    tcpSocket->write(btAry);

    /* 输出记录到 textBrowser */
    printLogOnTextBrowser("gimbal ctrl: up");
}

void MainWindow::toCtrlGimbalDown()
{
    QByteArray btAry;
    QJsonObject jsonObj;

    /* {"cmd":"control", "action":"down", "appid":"1000", "deviceid":"0001"} */
    jsonObj.insert("cmd", "control");
    jsonObj.insert("action", "down");
    jsonObj.insert("appid", "1000");
    jsonObj.insert("deviceid", "0001");

    /* 将json格式转换为byte数组 */
    QJsonDocument jsonDoc(jsonObj);
    btAry = jsonDoc.toJson();

    /* 往套接字写入数据 */
    tcpSocket->write(btAry);

    /* 输出记录到 textBrowser */
    printLogOnTextBrowser("gimbal ctrl: down");
}

void MainWindow::toCtrlGimbalLeft()
{
    QByteArray btAry;
    QJsonObject jsonObj;

    /* {"cmd":"control", "action":"left", "appid":"1000", "deviceid":"0001"} */
    jsonObj.insert("cmd", "control");
    jsonObj.insert("action", "left");
    jsonObj.insert("appid", "1000");
    jsonObj.insert("deviceid", "0001");

    /* 将json格式转换为byte数组 */
    QJsonDocument jsonDoc(jsonObj);
    btAry = jsonDoc.toJson();

    /* 往套接字写入数据 */
    tcpSocket->write(btAry);

    /* 输出记录到 textBrowser */
    printLogOnTextBrowser("gimbal ctrl: left");
}

void MainWindow::toCtrlGimbalRight()
{
    QByteArray btAry;
    QJsonObject jsonObj;

    /* {"cmd":"control", "action":"right", "appid":"1000", "deviceid":"0001"} */
    jsonObj.insert("cmd", "control");
    jsonObj.insert("action", "right");
    jsonObj.insert("appid", "1000");
    jsonObj.insert("deviceid", "0001");

    /* 将json格式转换为byte数组 */
    QJsonDocument jsonDoc(jsonObj);
    btAry = jsonDoc.toJson();

    /* 往套接字写入数据 */
    tcpSocket->write(btAry);

    /* 输出记录到 textBrowser */
    printLogOnTextBrowser("gimbal ctrl: right");
}

void MainWindow::toConnectTcpSocket()
{
    /* 判断套接字是否处于非连接状态 */
    if (tcpSocket->state() != tcpSocket->ConnectedState)
    {
        /* 输出记录到 textBrowser */
        printLogOnTextBrowser("to connect tcp...");

        /* 连接指定 IP 和 端口 */
        tcpSocket->connectToHost(ipLineEdit->text(), portLineEdit->text().toInt());

        /* 设置按键使能状态 */
        ipLineEdit->setEnabled(false);
        portLineEdit->setEnabled(false);

        connectBtn->setEnabled(false);
    }
}

void MainWindow::tcpConnected()
{
    QByteArray btAry;
    QJsonObject jsonObj;

    /* 判断套接字是否处于连接状态 */
    if (tcpSocket->state() == tcpSocket->ConnectedState)
    {
        /* 输出记录到 textBrowser */
        printLogOnTextBrowser("tcp connected to host");

        /*
         * 发送 Json指令: {"cmd":"get_video_data", "appid":"1000", "deviceid":"0001"}
         */
        jsonObj.insert("cmd", "get_video_data");
        jsonObj.insert("appid", "1000");
        jsonObj.insert("deviceid", "0001");

        /* 将json格式转换为byte数组 */
        QJsonDocument jsonDoc(jsonObj);
        btAry = jsonDoc.toJson();

        /* 往套接字写入数据 */
        tcpSocket->write(btAry);

        /* 设置按键使能状态 */
        ipLineEdit->setEnabled(false);
        portLineEdit->setEnabled(false);

        connectBtn->setEnabled(false);
        disconnectBtn->setEnabled(true);

        captureBtn->setEnabled(true);
        upendBtn->setEnabled(true);
        upBtn->setEnabled(true);
        downBtn->setEnabled(true);
        leftBtn->setEnabled(true);
        rightBtn->setEnabled(true);
    }
}

void MainWindow::toDisconnectTcpSocket()
{
    /* 判断套接字是否处于连接状态 */
    if (tcpSocket->state() == tcpSocket->ConnectedState)
    {
        /* 输出记录到 textBrowser */
        printLogOnTextBrowser("to disconnect tcp...");

        /* 断开连接 */
        tcpSocket->disconnectFromHost();

        /* 关闭 TCP 和 UDP 套接字 */
        tcpSocket->close();
        udpSocket->close();
    }
}

void MainWindow::tcpDisconnect()
{
    /* 判断套接字是否处于非连接状态 */
    if (tcpSocket->state() != tcpSocket->ConnectedState)
    {
        /* 输出记录到 textBrowser */
        printLogOnTextBrowser("tcp disconnected from host");

        /* 设置按键使能状态 */
        ipLineEdit->setEnabled(true);
        portLineEdit->setEnabled(true);

        connectBtn->setEnabled(true);
        disconnectBtn->setEnabled(false);

        captureBtn->setEnabled(false);
        upendBtn->setEnabled(false);
        upBtn->setEnabled(false);
        downBtn->setEnabled(false);
        leftBtn->setEnabled(false);
        rightBtn->setEnabled(false);
    }
}

void MainWindow::toSendAnyUdpData()
{
    QByteArray btAry = QString("any data").toUtf8();
    QHostAddress udpAddr = QHostAddress(ipLineEdit->text());

    /* 发送消息 */
    udpSocket->writeDatagram(btAry, udpAddr, udpPort);
}

void MainWindow::receivedReplyData()
{
    QJsonObject jsonObj;

    /* 读取接收到的数据 */
    QByteArray btAry = tcpSocket->readAll();

    /* 将数组转换为 QJsonObject */
    jsonObj = QJsonDocument::fromJson(btAry).object();

    /* 解析json数据 {"cmd":"port_info", "port":9500} */
    if (jsonObj.value("cmd").toString() == "port_info")
    {
        /* 解析出UDP端口号 */
        udpPort = jsonObj.value("port").toInt();

        /* 输出记录到 textBrowser */
        printLogOnTextBrowser("parsing udp port: " + QString::number(udpPort));

        /* 发出信号准备接收UDP数据 */
        emit readyToRecvUdp();
    }

    else if (jsonObj.value("cmd").toString() == "ctrlresponse")  /* {"cmd":"ctrlresponse", "result":"msg"} */
    {
        /* 输出记录到 textBrowser */
        printLogOnTextBrowser(jsonObj.value("result").toString());
    }
    else
    {
        printLogOnTextBrowser("cannot parsing tcp data");
    }
}

void MainWindow::receivedVideoDataAndShow()
{
    /* 局部变量，用于获取发送者的 IP 和端口 */
    QHostAddress peerAddr;
    quint16 peerPort;

    /* udpSocket 发送的数据报是 QByteArray 类型的字节数组 */
    QByteArray btAry;

    /* 如果有数据已经准备好 */
    while (udpSocket->hasPendingDatagrams())
    {
        /* 重新定义数组的大小 */
        btAry.resize(udpSocket->pendingDatagramSize());

        /* 读取数据，并获取发送方的 IP 地址和端口 */
        udpSocket->readDatagram(btAry.data(), btAry.size(),
                                &peerAddr, &peerPort);

        /* 输出记录到 textBrowser */
        printLogOnTextBrowser("recv video size: " + QString::number(btAry.size()));

        /* 显示图像 */
        QPixmap pix;
        pix.loadFromData(btAry);    /* 从数组加载数据 */
        picLabel->setPixmap(pix);   /* 将图片显示到label */
    }
}

void MainWindow::tcpSocketStateChange(QAbstractSocket::SocketState state)
{
    QString str = "tcp socket status: ";

    switch (state)
    {
        /* 套接字 未连接 状态 */
        case QAbstractSocket::UnconnectedState:
        {
            str.append("UnconnectedState");

            /* 设置按键使能状态 */
            ipLineEdit->setEnabled(true);
            portLineEdit->setEnabled(true);
            connectBtn->setEnabled(true);
        } break;

        /* 套接字 已连接 状态 */
        case QAbstractSocket::ConnectedState:
        {
            str.append("ConnectedState");
        } break;

        /* 套接字 连接中 状态 */
        case QAbstractSocket::ConnectingState:
        {
            str.append("ConnectingState");
        } break;

        /* 套接字 主机搜索 状态 */
        case QAbstractSocket::HostLookupState:
        {
            str.append("HostLookupState");
        } break;

        /* 套接字 关闭中 状态 */
        case QAbstractSocket::ClosingState:
        {
            str.append("ClosingState");
        } break;

        /* 套接字 监听中 状态 */
        case QAbstractSocket::ListeningState:
        {
            str.append("ListeningState");
        } break;

        /* 套接字 绑定 状态 */
        case QAbstractSocket::BoundState:
        {
            str.append("BoundState");
        } break;

        /* 套接字 未知 状态 */
        default:
        {
            str.append("Unknow");
        } break;
    }

    /* 输出记录到 textBrowser */
    printLogOnTextBrowser(str);
}

void MainWindow::udpSocketStateChange(QAbstractSocket::SocketState state)
{
    QString str = "udp socket status: ";

    switch (state)
    {
        /* 套接字 未连接 状态 */
        case QAbstractSocket::UnconnectedState:
        {
            str.append("UnconnectedState");
        } break;

        /* 套接字 已连接 状态 */
        case QAbstractSocket::ConnectedState:
        {
            str.append("ConnectedState");
        } break;

        /* 套接字 连接中 状态 */
        case QAbstractSocket::ConnectingState:
        {
            str.append("ConnectingState");
        } break;

        /* 套接字 主机搜索 状态 */
        case QAbstractSocket::HostLookupState:
        {
            str.append("HostLookupState");
        } break;

        /* 套接字 关闭中 状态 */
        case QAbstractSocket::ClosingState:
        {
            str.append("ClosingState");
        } break;

        /* 套接字 监听中 状态 */
        case QAbstractSocket::ListeningState:
        {
            str.append("ListeningState");
        } break;

        /* 套接字 绑定 状态 */
        case QAbstractSocket::BoundState:
        {
            str.append("BoundState");
        } break;

        /* 套接字 未知 状态 */
        default:
        {
            str.append("Unknow");
        } break;
    }

    /* 输出记录到 textBrowser */
    printLogOnTextBrowser(str);
}
